<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>弹幕分析</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    <script src="https://cdn.bootcdn.net/ajax/libs/echarts/5.4.3/echarts.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/echarts-wordcloud/2.0.0/echarts-wordcloud.min.js"></script>
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        bilibili: {
                            pink: '#FB7299',
                            blue: '#23ADE5',
                            dark: '#18191C',
                        }
                    }
                }
            }
        }
    </script>
    <style>
        @import url('https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700&display=swap');

        body {
            font-family: 'Noto Sans SC', sans-serif;
            background-color: #f5f5f5;
        }

        .danmu-card {
            background: white;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.05);
            transition: all 0.3s ease;
        }

        .danmu-card:hover {
            transform: translateY(-3px);
            box-shadow: 0 6px 15px rgba(0,0,0,0.1);
        }

        .danmu-item {
            padding: 10px 15px;
            border-bottom: 1px solid #f0f0f0;
            transition: all 0.2s;
        }

        .danmu-item:hover {
            background-color: #f9f9f9;
        }

        .loading-spinner {
            border: 4px solid rgba(0, 0, 0, 0.1);
            border-radius: 50%;
            border-top: 4px solid #FB7299;
            width: 40px;
            height: 40px;
            animation: spin 1s linear infinite;
            margin: 20px auto;
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }

        /* 弹幕展示区域样式 */
        #danmuContent {
            max-height: 600px;
            overflow-y: auto;
            scrollbar-width: thin;
            scrollbar-color: #FB7299 #f0f0f0;
        }

        #danmuContent::-webkit-scrollbar {
            width: 6px;
        }

        #danmuContent::-webkit-scrollbar-track {
            background: #f0f0f0;
            border-radius: 3px;
        }

        #danmuContent::-webkit-scrollbar-thumb {
            background-color: #FB7299;
            border-radius: 3px;
        }

        .search-highlight {
            background-color: #FFEB3B;
            font-weight: bold;
        }

        .refreshing {
            animation: spin 1s linear infinite;
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }

        .chart-container {
            width: 100%;
            height: 400px;
        }
    </style>
</head>
<body class="bg-gray-100">
<div class="min-h-screen">
    <nav class="bg-white shadow-sm">
        <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
            <div class="flex justify-between h-16">
                <div class="flex-shrink-0 flex items-center cursor-pointer hover:opacity-80 transition-opacity duration-200"
                     onclick="window.location.href = 'main'"
                     title="返回主页">
                    <i class="fab fa-bilibili text-3xl text-bilibili-pink hover:scale-105 transition-transform"></i>
                    <span class="ml-2 text-xl font-bold text-gray-800 hover:text-bilibili-pink transition-colors">视频弹幕</span>
                </div>
                <div class="flex items-center">
                    <a  onclick="window.location.href=`video?bvid=${bvid}`" class="text-gray-600 hover:text-bilibili-pink mr-4">
                        <i class="fas fa-arrow-left mr-1"></i>返回视频页
                    </a>
                </div>
            </div>
        </div>
    </nav>

    <main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">

        <div class="bg-white rounded-xl shadow-md overflow-hidden mb-8">
            <div class="p-6">
                <div class="flex flex-col md:flex-row justify-between items-start">
                    <div class="flex-1">
                        <h1 id="videoTitle" class="text-2xl font-bold text-gray-800 mb-2">加载中...</h1>
                        <div class="flex flex-wrap items-center text-sm text-gray-500 mb-4 gap-4">
                            <span><i class="fas fa-play mr-1"></i> 播放量: <span id="videoViews">--</span></span>
                            <span><i class="fas fa-heart mr-1"></i> 点赞数: <span id="videoLikes">--</span></span>
                            <span><i class="fas fa-comment-dots mr-1"></i> 评论数: <span id="videoComments">--</span></span>
                        </div>
                    </div>
                    <button id="videoLinkBtn" class="mt-4 md:mt-0 bg-bilibili-pink hover:bg-bilibili-blue text-white font-medium py-2 px-4 rounded-lg transition-all duration-300 flex items-center">
                        <i class="fas fa-external-link-alt mr-2"></i>
                        观看视频
                    </button>
                </div>
            </div>
        </div>

        <div class="flex justify-between items-center mb-6">
            <h1 class="text-2xl font-bold text-gray-800">弹幕内容</h1>
            <div class="text-sm text-gray-500">
<!--                <span id="danmuCount">0</span> 条弹幕-->
            </div>
        </div>

        <!-- 搜索框 -->
        <div class="mb-6 flex items-center justify-end gap-3">
            <button id="refreshDanmuBtn"
                    class="bg-bilibili-blue hover:bg-bilibili-pink text-white font-medium py-2 px-4 rounded-lg transition-all duration-300 flex items-center">
                <i class="fas fa-sync-alt mr-2"></i>
                更新弹幕数据
            </button>

            <div class="relative flex-1 max-w-xl ml-auto">
                <div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
                    <i class="fas fa-search text-gray-400"></i>
                </div>
                <input type="text" id="searchInput"
                       class="block w-full pl-10 pr-3 py-2 border border-gray-300 rounded-md leading-5 bg-white placeholder-gray-500 focus:outline-none focus:ring-bilibili-pink focus:border-bilibili-pink sm:text-sm"
                       placeholder="搜索弹幕内容...">
                <div class="absolute inset-y-0 right-0 pr-3 flex items-center">
                    <span id="searchCount" class="text-sm text-gray-500 hidden"></span>
                </div>
            </div>
        </div>

        <!-- 弹幕展示 -->
        <div class="danmu-card mb-8">
            <div class="p-4 border-b border-gray-100">
                <h2 class="text-lg font-semibold text-gray-800">全部弹幕内容</h2>
            </div>
            <div id="danmuContent" class="divide-y divide-gray-100">
                <div class="loading-spinner"></div>
            </div>
        </div>

        <!-- 词云 -->
        <div class="danmu-card mb-8">
            <div class="p-4 border-b border-gray-100">
                <h2 class="text-lg font-semibold text-gray-800">弹幕词云</h2>
            </div>
            <div id="danmuWordCloud" class="chart-container">
                <div class="loading-spinner"></div>
            </div>
        </div>

        <!-- 情感分析 -->
        <div class="bg-white rounded-xl shadow-md overflow-hidden card-hover mb-8">
            <div class="p-6">
                <h2 class="text-lg font-semibold text-gray-800 mb-4">评论情感分析</h2>
                <div id="sentimentChart" class="chart-container">
                    <div class="loading-spinner"></div>
                </div>
            </div>
        </div>

        <!-- 分析结果 -->
        <div class="danmu-card">
            <div class="p-4 border-b border-gray-100">
                <h2 class="text-lg font-semibold text-gray-800">分析结果</h2>
            </div>
            <div id="analysisResult" class="p-4">
                <div class="loading-spinner"></div>
            </div>
        </div>
    </main>
</div>

<script>
    const url = new URL(window.location.href);
    const params = new URLSearchParams(url.search);
    const bvid = params.get('bvid');

    if (!bvid) {
        alert(`未获取到bv号，请确认是否已输入`);
        window.location.href = `main`;
    }


    async function refreshDanmu() {
        const refreshBtn = document.getElementById('refreshDanmuBtn');
        const icon = refreshBtn.querySelector('i');

        try {

            refreshBtn.disabled = true;
            icon.classList.add('refreshing');

            const response = await fetch(`http://localhost:8080/v1/danmu/update/${bvid}`, {
                method: 'POST'
            });
            const result = await response.json();

            if (result.code % 2 === 0) {
                await loadAllData();
                showToast('弹幕更新成功', 'success');
            } else {
                showToast(`${result.msg}: ${result.data}`, 'error');
            }
        } catch (error) {
            console.error('更新弹幕失败:', error);
            showToast('更新弹幕失败: ' + error.message, 'error');
        } finally {
            refreshBtn.disabled = false;
            icon.classList.remove('refreshing');
        }
    }
    function showToast(message, type = 'info') {
        const toast = document.createElement('div');
        toast.className = `fixed top-4 right-4 px-4 py-2 rounded-md shadow-md text-white ${
            type === 'error' ? 'bg-red-500' :
                type === 'success' ? 'bg-green-500' :
                    'bg-bilibili-blue'
        }`;
        toast.textContent = message;
        document.body.appendChild(toast);

        setTimeout(() => {
            toast.classList.add('opacity-0', 'transition-opacity', 'duration-300');
            setTimeout(() => toast.remove(), 300);
        }, 3000);
    }

    async function fetchDanmuData() {
        try {
            const response = await fetch(`http://localhost:8080/v1/danmu/query/${bvid}`, {
                method: 'POST'
            });
            const result = await response.json();

            if (result.code % 2 === 0) {
                return result.data.map(item => item.danmu);
            } else {
                console.error('获取弹幕数据失败:', result.msg, result.data);
                document.getElementById('danmuContent').innerHTML = `
                    <div class="p-4 text-red-500">
                        <i class="fas fa-exclamation-triangle mr-2"></i>
                        ${result.msg}: ${result.data}
                    </div>
                `;
                return [];
            }
        } catch (error) {
            console.error('获取弹幕数据网络错误:', error);
            document.getElementById('danmuContent').innerHTML = `
                <div class="p-4 text-red-500">
                    <i class="fas fa-exclamation-triangle mr-2"></i>
                    获取失败，该视频可能还没有弹幕
                </div>
            `;
            return [];
        }
    }

    async function fetchVideoInfo() {
        try {
            const response = await fetch(`http://localhost:8080/v1/video/query/${bvid}`, {
                method: 'POST'
            });
            const result = await response.json();

            if (result.code % 2 === 0) {
                return result.data;
            } else {
                console.error('获取视频信息失败:', result.msg, result.data);
                return null;
            }
        } catch (error) {
            console.error('获取视频信息网络错误:', error);
            return null;
        }
    }

    async function fetchEmotionAnalysis() {
        try {
            const response = await fetch(`http://localhost:8080/v1/danmu/emo/${bvid}`, {
                method: 'POST'
            });
            const result = await response.json();

            if (result.code % 2 === 0) {
                return result.data;
            } else {
                console.error('获取情感分析失败:', result.msg, result.data);
                return null;
            }
        } catch (error) {
            console.error('获取情感分析网络错误:', error);
            return null;
        }
    }

    async function fetchWordCloudData() {
        try {
            const response = await fetch(`http://localhost:8080/v1/danmu/segmenter/${bvid}`, {
                method: 'POST'
            });
            const result = await response.json();

            if (result.code % 2 === 0) {
                return Object.entries(result.data).map(([name, value]) => ({
                    name,
                    value
                }));
            } else {
                console.error('获取词云数据失败:', result.msg, result.data);
                return null;
            }
        } catch (error) {
            console.error('获取词云数据网络错误:', error);
            return null;
        }
    }

    function updateVideoInfo(videoInfo) {
        if (!videoInfo) {
            document.getElementById('videoTitle').textContent = '获取视频信息失败';
            return;
        }

        document.getElementById('videoTitle').textContent = videoInfo.title || '无标题';
        document.getElementById('videoViews').textContent = videoInfo.playCount ? videoInfo.playCount.toLocaleString() : '--';
        document.getElementById('videoLikes').textContent = videoInfo.likeCount ? videoInfo.likeCount.toLocaleString() : '--';
        document.getElementById('videoComments').textContent = videoInfo.commentCount ? videoInfo.commentCount.toLocaleString() : '--';

        const videoLinkBtn = document.getElementById('videoLinkBtn');
        videoLinkBtn.onclick = () => {
            window.open(`https://www.bilibili.com/video/${bvid}`, '_blank');
        };
    }

    function initWordCloud(data) {
        const container = document.getElementById('danmuWordCloud');

        if (!data || data.length === 0) {
            container.innerHTML = '<div class="p-4 text-gray-500 text-center">暂无词云数据</div>';
            return;
        }

        container.innerHTML = ''; // 清除加载动画
        const chart = echarts.init(container);

        const option = {
            backgroundColor: '#ffffff',
            tooltip: {},
            series: [{
                type: 'wordCloud',
                shape: 'circle',
                left: 'center',
                top: 'center',
                width: '90%',
                height: '90%',
                right: null,
                bottom: null,
                sizeRange: [12, 60],
                rotationRange: [-45, 45],
                rotationStep: 15,
                gridSize: 8,
                drawOutOfBound: false,
                textStyle: {
                    fontFamily: 'Noto Sans SC',
                    fontWeight: 'bold',
                    color: function () {
                        return 'rgb(' +
                            Math.round(Math.random() * 155 + 100) + ',' +
                            Math.round(Math.random() * 155 + 100) + ',' +
                            Math.round(Math.random() * 155 + 100) + ')';
                    }
                },
                emphasis: {
                    focus: 'self',
                    textStyle: {
                        shadowBlur: 10,
                        shadowColor: '#333'
                    }
                },
                data: data
            }]
        };

        chart.setOption(option);

        window.addEventListener('resize', function() {
            chart.resize();
        });
    }

    function initSentimentChart(data) {
        const container = document.getElementById('sentimentChart');

        if (!data) {
            container.innerHTML = '<div class="text-gray-500 p-4 text-center">暂无情感分析数据</div>';
            return;
        }

        container.innerHTML = '';
        const chart = echarts.init(container);

        const total = data.积极 + data.中立 + data.消极;
        const positivePercent = total > 0 ? (data.积极 / total * 100).toFixed(1) : 0;
        const neutralPercent = total > 0 ? (data.中立 / total * 100).toFixed(1) : 0;
        const negativePercent = total > 0 ? (data.消极 / total * 100).toFixed(1) : 0;

        const option = {
            title: {
                text: '情感分布',
                left: 'center'
            },
            tooltip: {
                trigger: 'item',
                formatter: function(params) {
                    const percent = (params.value / total * 100).toFixed(2);
                    return `${params.name}<br>数量: ${params.value} (${percent}%)`;
                }
            },
            legend: {
                orient: 'vertical',
                left: 'left',
                data: ['积极', '中立', '消极']
            },
            series: [
                {
                    name: '情感分析',
                    type: 'pie',
                    radius: ['50%', '70%'],
                    avoidLabelOverlap: false,
                    itemStyle: {
                        borderRadius: 10,
                        borderColor: '#fff',
                        borderWidth: 2
                    },
                    label: {
                        show: false,
                        position: 'center'
                    },
                    emphasis: {
                        label: {
                            show: true,
                            fontSize: '18',
                            fontWeight: 'bold'
                        }
                    },
                    labelLine: {
                        show: false
                    },
                    data: [
                        {
                            value: data.积极,
                            name: `积极 (${positivePercent}%)`,
                            itemStyle: { color: '#4ade80' }
                        },
                        {
                            value: data.中立,
                            name: `中立 (${neutralPercent}%)`,
                            itemStyle: { color: '#60a5fa' }
                        },
                        {
                            value: data.消极,
                            name: `消极 (${negativePercent}%)`,
                            itemStyle: { color: '#f87171' }
                        }
                    ]
                }
            ]
        };

        chart.setOption(option);

        window.addEventListener('resize', function() {
            chart.resize();
        });
    }

    function loadDanmuContent(danmus) {
        const container = document.getElementById('danmuContent');
        container.innerHTML = '';

        if (!danmus || danmus.length === 0) {
            container.innerHTML = '<div class="p-4 text-gray-500 text-center">暂无弹幕数据</div>';
            return;
        }

        container._originalDanmus = danmus;

        const batchSize = 200;
        const totalBatches = Math.ceil(danmus.length / batchSize);

        let currentBatch = 0;

        function loadNextBatch() {
            const start = currentBatch * batchSize;
            const end = Math.min(start + batchSize, danmus.length);

            const fragment = document.createDocumentFragment();

            for (let i = start; i < end; i++) {
                const danmu = danmus[i];
                const item = document.createElement('div');
                item.className = 'danmu-item text-sm text-gray-700';
                item.textContent = danmu;
                item.dataset.original = danmu;
                fragment.appendChild(item);
            }

            container.appendChild(fragment);
            currentBatch++;

            if (currentBatch < totalBatches) {
                // 使用requestAnimationFrame分批加载以避免阻塞UI
                requestAnimationFrame(loadNextBatch);
            }
        }

        loadNextBatch();
    }

    function setupSearch() {
        const searchInput = document.getElementById('searchInput');
        const searchCount = document.getElementById('searchCount');
        const danmuContent = document.getElementById('danmuContent');

        searchInput.addEventListener('input', function() {
            const searchTerm = this.value.trim().toLowerCase();
            const items = danmuContent.querySelectorAll('.danmu-item');

            if (!searchTerm) {
                items.forEach(item => {
                    item.style.display = '';
                    item.innerHTML = item.dataset.original;
                });
                searchCount.classList.add('hidden');
                return;
            }

            let matchCount = 0;

            items.forEach(item => {
                const originalText = item.dataset.original;
                const lowerText = originalText.toLowerCase();

                if (lowerText.includes(searchTerm)) {
                    matchCount++;
                    item.style.display = '';

                    const highlightedText = originalText.replace(
                        new RegExp(searchTerm, 'gi'),
                        match => `<span class="search-highlight">${match}</span>`
                    );
                    item.innerHTML = highlightedText;
                } else {
                    item.style.display = 'none';
                }
            });


            searchCount.textContent = `${matchCount}条`;
            searchCount.classList.remove('hidden');
        });
    }

    function loadAnalysisResult(danmus) {
        const container = document.getElementById('analysisResult');
        container.innerHTML = '';

        if (!danmus || danmus.length === 0) {
            container.innerHTML = '<div class="p-4 text-gray-500 text-center">暂无分析数据</div>';
            return;
        }

        const analysisText = [
            `共分析 ${danmus.length} 条弹幕`,
            `发现 ${new Set(danmus).size} 种不同弹幕内容`,
            `弹幕多样性指数: ${(new Set(danmus).size / danmus.length * 100).toFixed(1)}%`
        ];

        // 添加文本分析结果
        analysisText.forEach(text => {
            const p = document.createElement('p');
            p.className = 'text-gray-600 mb-3';
            p.textContent = '• ' + text;
            container.appendChild(p);
        });
    }


    async function loadAllData() {
        try {
            const videoInfo = await fetchVideoInfo();
            updateVideoInfo(videoInfo);

            const danmus = await fetchDanmuData();

            const emotionData = await fetchEmotionAnalysis();

            const wordCloudData = await fetchWordCloudData();

            loadDanmuContent(danmus);
            initWordCloud(wordCloudData);
            initSentimentChart(emotionData);
            loadAnalysisResult(danmus);
            setupSearch();

            const analysisContainer = document.getElementById('analysisResult');
            analysisContainer.innerHTML = '';

            if (!danmus || danmus.length === 0) {
                analysisContainer.innerHTML = '<p class="text-gray-600">没有弹幕数据可供分析</p>';
                return;
            }

            let positivePercent = 0;
            let neutralPercent = 0;
            let negativePercent = 0;
            let totalSentiment = 0;

            if (emotionData) {
                totalSentiment = emotionData.积极 + emotionData.中立 + emotionData.消极;
                positivePercent = totalSentiment > 0 ? Math.round((emotionData.积极 / totalSentiment) * 100) : 0;
                neutralPercent = totalSentiment > 0 ? Math.round((emotionData.中立 / totalSentiment) * 100) : 0;
                negativePercent = totalSentiment > 0 ? Math.round((emotionData.消极 / totalSentiment) * 100) : 0;
            }

            let topKeywords = '无数据';
            if (wordCloudData && wordCloudData.length > 0) {
                topKeywords = wordCloudData
                    .sort((a, b) => b.value - a.value)
                    .slice(0, 5)
                    .map(item => item.name)
                    .join('、');
            }

            const uniqueDanmuCount = new Set(danmus).size;
            const diversityIndex = (uniqueDanmuCount / danmus.length * 100).toFixed(1);

            const analysisReport = [
                `📊 情感分布: 积极 ${positivePercent}% | 中立 ${neutralPercent}% | 消极 ${negativePercent}%`,
                `🔍 热门关键词: ${topKeywords}`,
                `💬 弹幕统计: ${uniqueDanmuCount} 种不同内容`,
                `📈 多样性指数: ${diversityIndex}%`,
                `${getResults(positivePercent, diversityIndex, neutralPercent)}`
            ];

            analysisReport.forEach(item => {
                const p = document.createElement('p');
                p.className = 'text-gray-600 mb-3';
                p.innerHTML = item;
                analysisContainer.appendChild(p);
            });

            function getResults(positivePercent, diversityIndex, neutralPercent) {
                let results = [];

                if (positivePercent < 40 && neutralPercent > 35) {
                    results.push('该视频议题存在争议，其观点或讨论对象可能不符合主流。');
                }

                if (diversityIndex < 30) {
                    results.push('弹幕内容重复率较高。');
                }

                return results.length > 0 ? results.join('') : '';
            }

        } catch (error) {
            console.error('加载数据失败:', error);
        }
    }

    window.addEventListener('load', async function() {
        document.getElementById('refreshDanmuBtn').addEventListener('click', refreshDanmu);
        await loadAllData();
    });
</script>
</body>
</html>